#pragma once

#include "Win32Painter.h"
#include "Image.h"

namespace sol9
{
namespace graphics
{

	__implementBaseClass(IPainter);
	__implementClass(Win32Painter, IPainter);

	Win32Painter::Win32Painter(HWND hDeviceWnd, core::dimension2du nScreenSize, eColorFormat eFormat)
		: m_hDeviceWnd(hDeviceWnd), m_nScreenSize(nScreenSize), m_eFormat(eFormat)
		, m_hPrimaryBuffer(nullptr), m_hBackBuffer(nullptr)
		, m_hDIBBuffer(nullptr), m_pBuffer(nullptr)
	{
		initialize();
	}

	Win32Painter::~Win32Painter()
	{
		if (m_pBuffer)
			m_pBuffer->detach();

		DeleteObject(m_hDIBBuffer);
		ReleaseDC(m_hDeviceWnd, m_hBackBuffer);
		ReleaseDC(m_hDeviceWnd, m_hPrimaryBuffer);
	}

	bool Win32Painter::initialize()
	{
		m_hPrimaryBuffer = GetDC(m_hDeviceWnd);

		if (!m_hPrimaryBuffer)
			return false;

		m_hBackBuffer = CreateCompatibleDC(m_hPrimaryBuffer);

		if (!m_hBackBuffer)
			return false;

		BITMAPINFO bi;
		ZeroMemory(&bi, sizeof(BITMAPINFO));
		bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		bi.bmiHeader.biWidth = m_nScreenSize.width;
		bi.bmiHeader.biHeight = -(s32)m_nScreenSize.height;
		bi.bmiHeader.biCompression = BI_RGB;
		bi.bmiHeader.biBitCount = IImage::getBitsPerPixelFromFormat(m_eFormat);
		bi.bmiHeader.biPlanes = 1;

		void* pRaster = nullptr;
		m_hDIBBuffer = CreateDIBSection(m_hBackBuffer, &bi, DIB_RGB_COLORS, &pRaster, NULL, 0);

		if (!pRaster)
			return false;

		m_pBuffer = new Image(m_eFormat, m_nScreenSize, pRaster, false);

		SelectObject(m_hBackBuffer, m_hDIBBuffer);
		return true;
	}

	bool Win32Painter::preDraw()
	{
		BitBlt(m_hBackBuffer, 0, 0, m_nScreenSize.width, m_nScreenSize.height, NULL, 0, 0, BLACKNESS);
		return true;
	}

	bool Win32Painter::postDraw()
	{
		BitBlt(m_hPrimaryBuffer, 0, 0, m_nScreenSize.width, m_nScreenSize.height, m_hBackBuffer, 0, 0, SRCCOPY);
		return true;
	}

	void Win32Painter::drawPixel(const core::position2di& Position, const color& cColor)
	{
		if (Position.x < 0 || Position.x >= (s32)m_nScreenSize.width)
			return;

		if (Position.y < 0 || Position.y >= (s32)m_nScreenSize.height)
			return;

		m_pBuffer->setPixel(Position.x, Position.y, cColor);
	}

	void Win32Painter::drawLine(const core::position2di& P1, const core::position2di& P2, const color& cColor)
	{
		//if (P1 == P2)
		//{
		//	drawPixel(P1, cColor);
		//	return;
		//}

		//if (P1.x == P2.x)
		//	_verticalLine(P1.x, P1.y, P2.y);
		//else if (P1.y == P2.y)
		//	_horizontalLine(P1.x, P2.x, P1.y);
		//else
		//	_bresenhamLine(P1.x, P1.y, P2.x, P2.y);
		
		HPEN curr = CreatePen(PS_SOLID, 1, RGB(cColor.r, cColor.g, cColor.b));
		HPEN prev = (HPEN)SelectObject(m_hBackBuffer, curr);
		MoveToEx(m_hBackBuffer, P1.x, P1.y, NULL);
		LineTo(m_hBackBuffer, P2.x, P2.y);
		SelectObject(m_hBackBuffer, prev);
		DeleteObject(curr);
	}

	void Win32Painter::drawImage(const core::position2di& Position, IImage* pImage)
	{
		if (!pImage)
			return;

		m_pBuffer->blit(pImage, Position);
	}

} // namespace graphics
} // namespace sol9